using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace PrototypeZGame
{
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        GraphicsDevice device;
        SpriteBatch spriteBatch;

        private World world;
        private Terrain terrain;
        private Camera2D playerCamera;
        private int lastScrollWheelValue;
        private MouseState mouseState;
        private KeyboardState keyboardState;
        private Texture2D mouseCursorNormal;

        private Texture2D textureBackgroundRight;
        private Texture2D textureBackgroundDown;
        private Texture2D textureInterface;
        private Texture2D textureGameOver;
        private string HUDText;
        private TimeSpan lastUpdateTime;
        private TimeSpan turnDelay = new TimeSpan(5000000); //100000 - for fast forward, 5000000 - watching
        private bool gameMode = true;

        

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }


        // any non-graphic
        protected override void Initialize()
        {
            graphics.PreferredBackBufferWidth = 1000 + 400;
            graphics.PreferredBackBufferHeight = 684 + 36 + 80;
            graphics.IsFullScreen = false;
            graphics.ApplyChanges();
            Window.Title = "ZGame";
       
            lastScrollWheelValue = Mouse.GetState().ScrollWheelValue;

            world = new World();
            world.fieldResolution = 32;
            world.DSR = 31;
            world.debugPathfinding = false;
            world.rand = new Random();

            playerCamera = new Camera2D(world);

            if (gameMode)
            {
                turnDelay = new TimeSpan(5000000);
            }
            else
            {
                turnDelay = new TimeSpan(100000); //100000 - for fast forward, 5000000 - watching
            }
            base.Initialize();
        }


        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);
            world.spriteBatch = spriteBatch;
            
            // Read screen resolution
            device = graphics.GraphicsDevice;
            world.screenWidth = 1000;
            world.screenHeight = 684;
            
            // Load textures
            world.tileset = Content.Load<Texture2D>("tileset_32");
            mouseCursorNormal = Content.Load<Texture2D>("NormalCursor");
            textureBackgroundRight = Content.Load<Texture2D>("backgroundRight");
            textureBackgroundDown = Content.Load<Texture2D>("backgroundDown");
            textureInterface = Content.Load<Texture2D>("interface");
            textureGameOver = Content.Load<Texture2D>("GameOver");

            // Load fonts
            world.screenFont = Content.Load<SpriteFont>("ScreenFont");

            // Generate terrain
            if (gameMode)
            {
                terrain = new Terrain(Content.Load<Texture2D>("Level2"), world);
            } 
            else
            {
                terrain = new Terrain(Content.Load<Texture2D>("Level3"), world);
            }

            // Add actors
            if (gameMode)
            {
                world.Spawn(new PlayerController(world, playerCamera), new Human(3, 4, world));
                playerCamera.centerOn(world.pc.unit);

                world.spawnHumans(20);
                world.spawnZombies(40);
            }
            else
            {
                world.pc = new PlayerController(world, playerCamera);
            }

        }




        protected override void UnloadContent()
        {
        }


        protected override void Update(GameTime gameTime)
        {
            // Clear screen log
            HUDText = "";

            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.Escape))
            {
                this.Exit();
            }
            mouseState = Mouse.GetState();
            keyboardState = Keyboard.GetState();
            
            UpdateCamera();
            world.pc.Update(keyboardState, mouseState);



            if (world.pc.finished && !world.pause && lastUpdateTime < gameTime.TotalGameTime - turnDelay)
            {
                lastUpdateTime = gameTime.TotalGameTime;
                world.endTurn();
            }

            if (!gameMode && (world.time - world.lastIterationTime >= world.maxIterationTime /*|| world.countAliveZombie()<=10*/ || world.countAliveHuman() <= 0))
            {
                world.nextIteration();
                world.lastIterationTime = world.time;
            }

            base.Update(gameTime);
        }
        

        protected void UpdateCamera()
        {            
            int delta = mouseState.ScrollWheelValue - lastScrollWheelValue;
            if (delta > 0)
            {
                playerCamera.scale *= 2.0f;
            }
            else if (delta < 0)
            {
                playerCamera.scale /= 2.0f;
            }
            lastScrollWheelValue = mouseState.ScrollWheelValue;
            
            float moveSpeed = 10.0f;

            if (keyboardState.IsKeyDown(Keys.Up)) playerCamera.move(0.0f, moveSpeed);
            if (keyboardState.IsKeyDown(Keys.Down)) playerCamera.move(0.0f, -moveSpeed);
            if (keyboardState.IsKeyDown(Keys.Left)) playerCamera.move(moveSpeed, 0.0f);
            if (keyboardState.IsKeyDown(Keys.Right)) playerCamera.move(-moveSpeed, 0.0f);

        }


        protected override void Draw(GameTime gameTime)
        {
            DrawWorld();
            DrawHUD();            
            base.Draw(gameTime);            
        }

        protected void DrawWorld()
        {
            world.fieldsDrawn = 0;

            GraphicsDevice.Clear(Color.Gray);
            world.globalTransformation = Matrix.CreateTranslation(-world.screenWidth / 2, -world.screenHeight / 2, 0) * playerCamera.getCameraMatrix() * Matrix.CreateTranslation(world.screenWidth / 2, world.screenHeight / 2, 0);


            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, null, null, null, null, world.globalTransformation);

            // Unproject corners of the screen
            Vector2 vecUL = screenToWorld(Vector2.Zero);
            Vector2 vecDR = screenToWorld(new Vector2(world.screenWidth, world.screenHeight));
            world.mouseWorldPosition = screenToWorld(new Vector2(mouseState.X, mouseState.Y));
            terrain.MouseOver(world.mouseWorldPosition);
            terrain.Draw((int)vecUL.X / world.fieldResolution, (int)vecUL.Y / world.fieldResolution, (int)vecDR.X / world.fieldResolution, (int)vecDR.Y / world.fieldResolution);


            if (world.debugPathfinding && world.pathFindingResult != null)
            {
                for (int x = 0; x < world.pathFindingResult.GetLength(0); x++)
                {
                    for (int y = 0; y < world.pathFindingResult.GetLength(1); y++)
                    {
                        if (world.pathFindingResult[x, y] < int.MaxValue)
                        {
                            world.spriteBatch.DrawString(world.screenFont, world.pathFindingResult[x, y].ToString(), new Vector2((x + world.pc.getUnitPos().x - world.DSR) * world.fieldResolution, (y + world.pc.getUnitPos().y - world.DSR) * world.fieldResolution), Color.White);
                        }
                    }
                }
            }

            spriteBatch.End();

            HUDText += "Time: " + world.time + "\n"
                    + "Humans: " + world.countAliveHuman() + " | Zombies:" + world.countAliveZombie() + "\n"
                    + "Paused: " + world.pause + "\n"
                    + "FieldsDrawn: " + world.fieldsDrawn + "\n"
                    + "Scale: " + playerCamera.scale + "\n"
                    + "UL: " + vecUL + "\n"
                    + "DR: " + vecDR + "\n"
                    + "mouseWorldPosition: " + world.mouseWorldPosition + "\n";

        }

        protected void DrawHUD()
        {
            // Draw HUD
            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, null, null, null, null, Matrix.Identity);
            spriteBatch.Draw(textureBackgroundRight, new Vector2(world.screenWidth, 0), Color.White);
            spriteBatch.Draw(textureBackgroundDown, new Vector2(0, world.screenHeight), Color.White);
            spriteBatch.DrawString(world.screenFont, HUDText, Vector2.Zero, Color.White);

            spriteBatch.DrawString(world.screenFont, world.pc.getInfoString(), new Vector2(world.screenWidth + 10, 220), Color.White);
            
            Field pointedField = terrain.worldPositionToField(world.mouseWorldPosition);
            if (pointedField != null)
            {
                spriteBatch.DrawString(world.screenFont, pointedField.getFieldInfoString(), new Vector2(world.screenWidth + 10, 400), Color.White);
            }

            DrawItemsOnCurrentField();
            DrawItemsInEquipment();
            DrawPlayerStats();

            if (world.pc.state == PlayerController.State.Dead)
            {
                spriteBatch.Draw(textureGameOver, new Vector2(100,300), Color.White);
            }

            // It has to be last thing drawn
            spriteBatch.Draw(mouseCursorNormal, new Vector2(mouseState.X, mouseState.Y), Color.White);
            spriteBatch.End();
        }

        protected void DrawPlayerStats()
        {
            Human player = world.pc.unit as Human;
            if (player == null)
            {
                return;
            }

            // HP
            int width = (int)(player.HP / player.maxHP * 200);
            Rectangle sourceRectangle = new Rectangle(0, 0, width, 18);
            Rectangle destinationRectangle = new Rectangle(world.screenWidth + 34, 22, width, 18);
            spriteBatch.Draw(textureInterface, destinationRectangle, sourceRectangle, Color.White);

            // EL
            width = (int)(player.EL / player.maxEL * 200);
            sourceRectangle.Y = 18;
            sourceRectangle.Width = width;
            destinationRectangle.Y = 45;
            destinationRectangle.Width = width;
            spriteBatch.Draw(textureInterface, destinationRectangle, sourceRectangle, Color.White);

            // FL
            width = (int)(player.FL / player.maxFL * 200);
            sourceRectangle.Y = 36;
            sourceRectangle.Width = width;
            destinationRectangle.Y = 68;
            destinationRectangle.Width = width;
            spriteBatch.Draw(textureInterface, destinationRectangle, sourceRectangle, Color.White);

        }

        protected void DrawItemsOnCurrentField()
        {
            if (world.pc.unit == null) return;
            Field currentField = world.terrain.getField(world.pc.unit.position);
            Rectangle destinationRectangle = new Rectangle(world.screenWidth + 35, 172, world.fieldResolution, world.fieldResolution);
            foreach(InventoryItem i in currentField.onFieldInventoryItems)
            {
                spriteBatch.Draw(world.tileset,destinationRectangle,i.sourceRectangle,Color.White);
                destinationRectangle.X += 33;
            }
        }

        protected void DrawItemsInEquipment()
        {
            if (world.pc.unit == null) return;
            Rectangle destinationRectangle = new Rectangle(world.screenWidth + 35, 135, world.fieldResolution, world.fieldResolution);
            Rectangle inUseRectangle = new Rectangle(((int)TileType.ItemInUse % 16) * world.fieldResolution, world.fieldResolution * ((int)TileType.ItemInUse / 16), world.fieldResolution, world.fieldResolution);
            foreach (InventoryItem i in world.pc.unit.inventory.items)
            {
                spriteBatch.Draw(world.tileset, destinationRectangle, i.sourceRectangle, Color.White);
                if (i.inUse)
                {
                    spriteBatch.Draw(world.tileset, destinationRectangle, inUseRectangle, Color.White);
                }
                destinationRectangle.X += 33;
            }
        }

        protected Vector2 screenToWorld(Vector2 screenPosition)
        {
            Vector3 vec = device.Viewport.Unproject(
                new Vector3(screenPosition.X, screenPosition.Y, 0.0f),
                Matrix.CreateOrthographicOffCenter(0, device.Viewport.Width, device.Viewport.Height, 0, 0, 1),
                world.globalTransformation,
                Matrix.Identity
                );
            return new Vector2(vec.X, vec.Y);
        }











        //private void migrateHuman()
        //{
        //    int x, y;

        //    do
        //    {
        //        x = world.rand.Next(terrain.X);
        //        y = world.rand.Next(terrain.Y);
        //    } while (terrain.blocking(x, y) != Result.NoBlock);

        //    int[] DNA = {
        //                                   world.rand.Next(40) + 1,
        //                                   world.rand.Next(40) + 1,
        //                                   world.rand.Next(40) + 1,
        //                                   world.rand.Next(40) + 1,
        //                                   world.rand.Next(40) + 1,
        //                                   world.rand.Next(40) + 1,
        //                                   world.rand.Next(40) + 1,
        //                               };

        //    world.Spawn(new FuzzyHumanAI(world, DNA), new Human(x, y, world));
        //}


    }
}



